package com.skymxc.clickroute;

import android.app.Activity;
import android.util.Log;
import android.view.View;

import com.skymxc.annotation.OnClick;
import com.skymxc.annotation.OnLongClick;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * <p>
 * 点击事件路由
 * </p>
 *
 * @author 孟祥超
 * <p>
 * date: 2021/8/9
 */
public class ClickRoute {

    public static final String TAG = ClickRoute.class.getSimpleName();

    /**
     * 动态代理的形式实现
     * 使用动态代理生成了 OnClickListener ,onLongClickListener 的代理类，真实实现交到了ClickInvocationHandler 里 反射调用真实方法
     * 反射获取到标注注解的方法，获取到 id，找到 View 然后设置点击事件。
     * @param activity
     */
    public static void proxyBind(Activity activity){
        //动态生成的代理类
        ClickInvocationHandler clickInvocationHandler = new ClickInvocationHandler(activity);
        View.OnClickListener onClickListener = (View.OnClickListener) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{View.OnClickListener.class},
                clickInvocationHandler);
        ClickInvocationHandler onLongClickInvocationHandler = new ClickInvocationHandler(activity);
        View.OnLongClickListener onLongClickListener = (View.OnLongClickListener) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{View.OnLongClickListener.class},onLongClickInvocationHandler);
        Class<? extends Activity> activityClass = activity.getClass();
        //找到标注了 onCLick 和 onLongClick 的方法

        Method[] declaredMethods = activityClass.getDeclaredMethods();
        if (null != declaredMethods && declaredMethods.length > 0) {

            for (Method method : declaredMethods) {
                Log.i(TAG, "bind: method->"+method.getName());
                OnClick onClick = method.getAnnotation(OnClick.class);
                if (null != onClick) {
                    //说明此方法标注了 onClick 注解
                    verifyParameterType(activityClass,method);
                    int[] value = onClick.value();
                    if (null!=value && value.length>0){
                        for (int id :value){
                            View view = activity.findViewById(id);
                            if (null!=view){
                                view.setOnClickListener(onClickListener);
                                clickInvocationHandler.addViewMethod(id,method);
                            }
                        }
                    }
                }
                OnLongClick onLongClick = method.getAnnotation(OnLongClick.class);
                if (null!=onLongClick){
                    verifyParameterType(activityClass,method);
                    Class<?> returnType = method.getReturnType();
                    if (null==returnType){
                        throw new IllegalArgumentException(activityClass.getSimpleName()+" 里的"+method.getName()+" 的方法，返回类型必须是 boolean 类型 ，目前没有返回");
                    }
                    if (!returnType.getName().equals(boolean.class.getSimpleName())){
                        throw new IllegalArgumentException(activityClass.getSimpleName()+" 里的"+method.getName()+" 的方法，返回类型必须是 "+boolean.class.getSimpleName()+" 类型，目前是"+returnType.getName());
                    }
                    int[] value = onLongClick.value();
                    if (null!=value && value.length>0){
                        for (int id :value){
                            View view = activity.findViewById(id);
                            if (null!=view){
                                view.setOnLongClickListener(onLongClickListener);
                                onLongClickInvocationHandler.addViewMethod(id,method);
                            }
                        }
                    }
                }
            }

        }
    }

    /**
     * 通过反射的形式调用
     * 使用静态代理的方式，创建了点击事件的代理类，在代理类里调用了注解方法。
     * @param activity
     */
    public static void reflectBind(Activity activity) {
        /**
         * 1.反射获取到 activity 内标注了 onClick onLongClick 的注解方法
         * 2.获取到 value 里的 id 通过 找到控件
         * 3.为控件设置一个侦听器，从侦听器里回调 Activity 的注解方法
         */
        Class<? extends Activity> activityClass = activity.getClass();
            //找到标注了 onCLick 和 onLongClick 的方法

            Method[] declaredMethods = activityClass.getDeclaredMethods();
            if (null != declaredMethods && declaredMethods.length > 0) {

                for (Method method : declaredMethods) {
                    Log.i(TAG, "bind: method->"+method.getName());
                    OnClick onClick = method.getAnnotation(OnClick.class);
                    if (null != onClick) {
                        //说明此方法标注了 onClick 注解
                        verifyParameterType(activityClass,method);

                        int[] value = onClick.value();
                        if (null!=value && value.length>0){
                            OnClickWrap onClickWrap = new OnClickWrap(method,activity);
                            for (int id :value){
                                View view = activity.findViewById(id);
                                if (null!=view){
                                    view.setOnClickListener(onClickWrap);
                                }
                            }
                        }
                    }
                    OnLongClick onLongClick = method.getAnnotation(OnLongClick.class);
                    if (null!=onLongClick){
                        verifyParameterType(activityClass,method);
                        Class<?> returnType = method.getReturnType();
                        if (null==returnType){
                            throw new IllegalArgumentException(activityClass.getSimpleName()+" 里标注了 "+OnLongClick.class.getSimpleName()+" 的方法，返回类型必须是 boolean 类型 ，目前没有返回");
                        }
                        if (!returnType.getName().equals(boolean.class.getSimpleName())){
                            throw new IllegalArgumentException(activityClass.getSimpleName()+" 里标注了 "+OnLongClick.class.getSimpleName()+" 的方法，返回类型必须是 "+boolean.class.getSimpleName()+" 类型，目前是"+returnType.getName());
                        }
                        int[] value = onLongClick.value();
                        if (null!=value && value.length>0){
                            OnLongClickWrap onLongClickWrap = new OnLongClickWrap(method,activity);
                            for (int id :value){
                                View view = activity.findViewById(id);
                                if (null!=view){
                                    view.setOnLongClickListener(onLongClickWrap);
                                }
                            }
                        }
                    }
                }

            }

    }

    private static void verifyParameterType(Class<? extends Activity> activityClass,Method method){
        Class<?>[] parameterTypes = method.getParameterTypes();
        if (null==parameterTypes||parameterTypes.length==0){
            //没有声明参数，
            throw new IllegalArgumentException(activityClass.getSimpleName()+" 里的方法："+method.getName()+" ，必须含有一个 View 形参，目前没有声明。");
        }else if (parameterTypes.length>1){
            throw new IllegalArgumentException(activityClass.getSimpleName()+" 里的方法："+method.getName()+" 的方法，只能有一个 View 形参，目前有 "+parameterTypes.length+" 个形参。");
        }else {
            Class<?> parameterType = parameterTypes[0];
            if (!parameterType.getName().equals(View.class.getName())){
                throw new IllegalArgumentException(activityClass.getSimpleName()+" 里的方法："+method.getName()+" 的方法形参必须是 "+View.class.getName()+",目前是"+parameterType.getName());
            }
        }
    }
}
